﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using log4net;

namespace RollBackLib.src.core
{

    /// <summary>
    /// Stasticstics about the current backup operation
    /// </summary>
    [Serializable]
    public class BackupStatistics
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(BackupStatistics));

        public class FileType
        {
            public long m_count;
            public long m_totalSize;
            public Regex m_filePattern = new Regex("");
            public bool m_matchUsingRegexp = true;

            public String m_name = "";

            public FileType()
            {
            }

            public FileType(String name,String regexp,bool matchUsingRegexp)
            {
                //m_fileExtn = new Regex("\\.(mov)|(mp4)(avi)|(divx)|(flv)|(mpeg.)|(mpg)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
                m_filePattern = new Regex(regexp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
                m_name = name;
                m_matchUsingRegexp = matchUsingRegexp;
            }

            public void reset()
            {
                m_count = 0;
                m_totalSize = 0;
            }
        }

        /// <summary>
        /// Count of the various file types according to their extension.
        /// </summary>
        public class FileTypeCount
        {
            public FileType m_images;
            public FileType m_videos;
            public FileType m_documents;
            public FileType m_zipFiles;
            public FileType m_audioFiles;
            public FileType m_exeFiles;

            /// <summary>
            /// Remaining files which don't fall into any category
            /// </summary>
            public FileType m_others;

            public List<FileType> m_typeList = new List<FileType>();


            public FileTypeCount()
            {
                m_videos = new FileType("Videos", "(asf)|(divx)|(m2t)|(m2t.)|(mov)|(mp4)|(avi)|(divx)|(flv)|(mpeg.)|(mpg)|(ogg)|(ogm)|(ogv)|(ogx)|(vob)|(wmv)|(iso)",true);
                m_documents = new FileType("Documents","(doc)|(txt)|(xml)|(xls)|(pdf)|(htm)|(html)",true);
                m_images = new FileType("Images","(jpg)|(jpeg)|(gif)|(bmp)|(png)|(tif)|(tiff)|(dib)",true);
                m_zipFiles = new FileType("ZipFiles","(cab)|(zip)",true);
                m_audioFiles = new FileType("Audio", "(aac)|(ac3)|(wav)|(m4p)|(mp3)|(wma)|(au)|(m4a)|(rm)|(m3u)",true);
                m_exeFiles = new FileType("Binaries", "(exe)|(dll)|(db)|(ini)|(thm)|(ifo)", true);
                m_others = new FileType("Others", "", false);
                m_typeList.Add(m_images);
                m_typeList.Add(m_videos);
                m_typeList.Add(m_documents);
                m_typeList.Add(m_zipFiles);
                m_typeList.Add(m_audioFiles);
                m_typeList.Add(m_exeFiles);
                m_typeList.Add(m_others);
            }
            public void reset()
            {
                foreach (FileType t in m_typeList)
                {
                    t.reset();
                }
            }
        }

        /// <summary>
        /// Statistics about files/folder operations
        /// </summary>
        public class FileStats
        {
            public long m_deleted = 0;
            /// <summary>
            /// total number of directories copied so far
            /// </summary>
            public long m_copied = 0;

            /// <summary>
            /// Newly created directories
            /// </summary>
            public long m_created = 0;

            public long m_skipped = 0;

            /// <summary>
            /// Total size of all the files looked at in the source directory not necessarily copied
            /// </summary>
            public long m_totalBytesScanned;

            public long m_totalBytesCopied = 0;

            /// <summary>
            /// How much portion of the file/folder have been copied.
            /// 1. In the case of files this is the number of bytes, in the case of folders this is the number of items
            /// 2. In the folder which have been processed.
            /// has been copied.
            /// </summary>
            public long m_inProgress = 0;

            /// <summary>
            /// 1. For files this is the size of the file that is being copied.
            /// 2. For folders this is always the sub item (within the folder) that is currently being processed
            /// </summary>
            public long m_currentSize = 0;

            /// <summary>
            /// Number of errors during copy operation.
            /// </summary>
            public long m_numErrors = 0;

            public void Reset()
            {
                m_deleted = 0;
                m_copied = 0;
                m_created = 0;
                m_skipped = 0;
                m_totalBytesCopied = 0;
                m_totalBytesScanned = 0;
                m_currentSize = 0;
                m_inProgress = 0;
                m_inProgress = 0;
                m_currentSize = 0;
                m_numErrors = 0;
            }
        };

        /// <summary>
        /// Statistics on directories
        /// </summary>
        public FileStats m_dirStats = new FileStats();

        public FileStats m_fileStats = new FileStats();

        public FileTypeCount m_typeCount = new FileTypeCount();

        public JobId m_Id = null;

        public CurrentOperation m_operation;

        /// <summary>
        /// Information about the current operation being performed,
        /// eg:- "Copying file from source to destination
        /// </summary>
        public string m_operationMsg;

        /// <summary>
        /// backup operation was aborted by user
        /// </summary>
        public bool m_backupWasStopped;


        /// <summary>
        /// Set to true if the early exit notification was already passed to the statusupdate routine
        /// to prevent repetitive notification.
        /// </summary>
        public bool m_earlyExitNotified;

        /// <summary>
        /// Any system error that occured during the copy operation
        /// </summary>
        public int m_systemError;

        /// <summary>
        /// Current source location of file/directory being copied
        /// </summary>
        public string m_currentSource;

        /// <summary>
        /// The location where the file/directory is being copied to.
        /// </summary>
        public string m_currentDestination;

        public DateTime m_started;

        public DateTime m_stopped;

        public BackupInfo.LastRunResult m_lastRunSuccess = BackupInfo.LastRunResult.FAILED;

        /// <summary>
        /// The type of backup operation that was attempted, like BACKUP,RESTORE,DELETE etc.
        /// </summary>
        public BackupInfo.BackupType m_BackupType
        {
            get;
            set;
        }

        /// <summary>
        /// List of the first few directories created
        /// </summary>
        public List<String> m_dirsCreated = new List<string>();

        public List<String> m_dirsPruned = new List<string>();

        public void resetCounters()
        {
            m_dirStats.Reset();
            m_operation = CurrentOperation.Finished;
            
            m_fileStats.Reset();
            m_dirStats.Reset();

            m_operationMsg = "";
            m_backupWasStopped = false;
            m_earlyExitNotified = false;
            m_systemError = 0;
            m_currentSource = "";
            m_currentDestination = "";
            m_dirsCreated.Clear();
            m_dirsPruned.Clear();
        }

        /// <summary>
        /// collect statistics about the file type etc
        /// </summary>
        /// <param name="file"></param>
        internal void collectStatistics(System.IO.FileInfo file)
        {
            if (file != null)
            {
                do
                {
                    bool found = false;
                    foreach (FileType type in m_typeCount.m_typeList)
                    {
                        if (type.m_matchUsingRegexp && type.m_filePattern.IsMatch(file.Extension))
                        {
                            type.m_count++;
                            type.m_totalSize += file.Length;
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        m_typeCount.m_others.m_count++;
                        m_typeCount.m_others.m_totalSize += file.Length;
                        log.Info("Other file type is <" + file.DirectoryName + "/" + file.Name + ">");
                    }
                } while (false);
            }
            else if (m_operation == CurrentOperation.CreatingDirectory)
            {
                if (m_dirsCreated.Count < 10 && m_currentSource != null)
                {
                    // collect the first few directores created
                    m_dirsCreated.Add(m_currentSource);
                }
            }
            else if (m_operation == CurrentOperation.PruningDirectoryItem)
            {
                if (m_dirsPruned.Count < 10 && m_currentDestination != null)
                {
                    m_dirsPruned.Add(m_currentDestination);
                }
            }
        }
    };
}
